package com.xpec.c4.game.character;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.itembox.ChangeItem;
import com.ms.game.itembox.ChangeItemLister;
import com.ms.game.itembox.ItemChangeParam;
import com.ms.game.itembox.db.ItemChangeProcessData;
import com.ms.game.itembox.db.ItemDAO;
import com.ms.player.Player;
import com.ms.player.PlayerUserType;
import com.ms.player.UpdateAttribute;
import com.ms.player.UpdateAttributeList;
import com.ms.service.error.ErrorCode;
import com.ms.service.module.account.Account;
import com.ms.service.module.account.db.AccountDAO;
import com.ms.service.module.analysis.message.PlayerBetData;
import com.ms.service.module.analysisgroup.AnalysisGroupProcessor;
import com.xpec.c4.db.dao.PlayerDAO;
import com.xpec.c4.db.model.PlayerModel;
import com.xpec.c4.game.common.Helper;
import com.xpec.c4.game.datamanager.agent.money.ChangeCoinLister;
import com.xpec.c4.game.datamanager.agent.money.CoinType;
import com.xpec.c4.game.datamanager.agent.money.MoneyChangeParam;
import com.xpec.c4.game.datamanager.agent.moneyItem.MoneyItemChangeParam;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ModuleName;
import com.xpec.c4.service.module.ServerProperties;
import com.xpec.c4.service.module.datacenter.player.UpdateH5PlayerMoneyToDbAsync;

/**
 * 玩家对象管理，可组内共享
 * 
 * @author lipeilin
 * @2011-2-21 下午04:08:48
 * 
 */
public class PlayerManager {

	private static final Log log = LogFactory.getLog(PlayerManager.class);

	private static final PlayerManager instance = new PlayerManager();
	
	private PlayerManager() {

	}

	public static PlayerManager getInstance() {
		return instance;
	}
	
	/**
	 * 通过GUID取得对象<br>
	 * 从ShareMap读取，没有的话从DB读取，并放回ShareMap
	 * 
	 * @param guid
	 * 
	 * @author lipeilin
	 * @2011-2-21 下午05:00:01
	 */
	@Deprecated
	public Player getPlayerInDBCache(GUID guid) {

		/*
		Player player = playerShares.get(guid);

		// 如果没有就从DB读取
		if (player == null) {
			player = loadPlayerFromDB(guid, true);
			log.info("load from DB:" + player);
			return player;
		} else {
			player.setLoadTime(System.currentTimeMillis());
			log.info("load from cache:" + player);
			return player;
		}
		*/
		
		return null;
	}
	
	/**
	 * 更新角色資料到 DB
	 * 
	 * @param player
	 *            player data
	 * @return true 成功<br>
	 *         false 失敗
	 */
	public boolean updatePlayerToDB(Player player) {
		boolean res;
		try {
			res = PlayerDAO.saveOrUpdatePlayer(player);
			if (log.isInfoEnabled()) {
				log.info("update player " + player.getGuid() + " to db");
			}
		} catch (Exception e) {
			log.error("cannot update player:" + player.getGuid(), e);
			throw new RuntimeException(e);
		}

		return res;
	}

	/**
	 * 變更角色金錢數值
	 * 
	 * @param currentModule
	 *            目前所在的 module
	 * @param param
	 *            變更角色金錢的相關參數<br>
	 *            取得變更作業執行結果代碼 {@link MoneyChangeParam#getResult() }<br>
	 *            取得金錢變更後的新數值 {@link MoneyChangeParam#getNewValue() }
	 */
	public void updatePlayerMoneyToDB(Player player, BasicServiceModule currentModule, MoneyChangeParam param) {
		if (param == null) {
			return;
		}

		try {
			// 扣錢的相關參數檢查
			PlayerDAO.changeMoneyVerify(player, param);

			// 成功後數值套回 db
			if (param.getResult() == ErrorCode.SUCCESS)
			{
				PlayerDAO.changeMoneyApply(param, player);
			}
			
			// 失敗顯示 log
			if (param.getResult() != ErrorCode.SUCCESS) {
				if (log.isErrorEnabled()) {
					log.error(param.getResultString());
				}
				return;
			}

			// 顯示 log
			if (log.isInfoEnabled() && ServerProperties.isSaveConsoleLog(param.getUserType())) {
				log.info(param.getResultString());
			}
		} catch (Exception e) {
			log.error("can't change player money: " + param.getPlayerName() + " result=" + param.getResult(), e);
			throw new RuntimeException(e);
		}

		if (param.getResult() == ErrorCode.SUCCESS) {
			// 如果是玩家押注
			if (param.getChangeWay().isDailyBet()) {
				// 如果是真人玩家才處理送即時總押注紀錄給analysis module
				if(player.getUserType() == PlayerUserType.PLAYER){
					PlayerBetData playerBetData = new PlayerBetData();
					playerBetData.setGuid(player.getGuid().toString());
					playerBetData.setGameName(param.getGameId());
					playerBetData.setHallType(param.getGameHallId());
					playerBetData.setPlatform(player.getLastLoginPlatform());
					playerBetData.setTrialAccount(player.isTrialAccount());
					playerBetData.setOfflineSpin(param.isOfflineSpin());
					ChangeCoinLister coinLister = param.getChangeCoinLister();				
					if(coinLister.getCoinMap().containsKey(CoinType.TRIAL)){
						playerBetData.setUseTrialCoin(true);
						playerBetData.setBet(coinLister.getCoinMap().get(CoinType.TRIAL).getChangeValue().toString());
					}
					else{
						playerBetData.setBet(coinLister.getCoinMap().get(CoinType.GOLD).getChangeValue().toString());
					}
					GroupMessage msg = new GroupMessage();
					msg.setDestModuleID(ModuleName.ANALYSIS);
					msg.setMessageType(MessageTypes.S_ANALYSIS_PLAYER_BET);
					msg.setMessageContent(playerBetData);
					MessageAction.sendMessage(msg);
				}
			} // if (param.getChangeWay().isDailyBet()) {
			
			//analysis group module統計收入與支出
			if(player.getUserType() == PlayerUserType.PLAYER && param.getChangeCoinLister().getSize() > 0 &&
			   (param.getChangeWay().isDailyBet() || param.getChangeWay().isDailyScore())){
				AnalysisGroupProcessor.OnSendRevenueAndExpenditureToAnalysisGroup(param);
			}
			
			// save player
			PlayerDAO.savePlayerToRedis(player);
			
			// 錢更新回 db
			UpdateH5PlayerMoneyToDbAsync async =  new UpdateH5PlayerMoneyToDbAsync();
			async.initial(player.getGuid(), player.getGoldCoin(), null);
			
			currentModule.addAsyncCommand(async);
		} // if (param.getResult() == ErrorCode.SUCCESS) {
	}
	
	/**
	 * 變更角色道具數量
	 * 
	 * @param param
	 *            變更角色道具的相關參數<br>
	 *            取得變更作業執行結果代碼 {@link ItemChangeParam#getResult() }<br>
	 *            取得道具變更後的新數量 {@link ChangeItem#getNewCount() }
	 */
	public void updatePlayerItemToDB(BasicServiceModule currentModule, ItemChangeParam param) {
		if (param == null) {
			return;
		}

		try {
			UpdateAttributeList updateAttributeList = new UpdateAttributeList();

			// 扣道具的相關參數檢查
			ItemChangeProcessData itemChangeProcData = ItemDAO.changeItemVerify(param);

			// 成功後數值套回 db
			if (param.getResult() == ErrorCode.SUCCESS) {
				ItemDAO.changeItemApply(param, itemChangeProcData, updateAttributeList);
			
				// 這次道具更變需要增加經驗
				if(Helper.isGreaterThanZero(param.getExpChangeValue())) {
					PlayerModel model = PlayerDAO.loadPlayerModelByGuid(param.getPlayerId());
					PlayerDAO.updatePlayerExpByItem(currentModule, param, model, updateAttributeList);
					PlayerDAO.updatePlayerFromAttrList(model.getGuid(), updateAttributeList.getUpdateList(), param.getUserType());
				}
				
				param.setUpdatedAttrList(updateAttributeList.getUpdateList());
			}

			// 失敗顯示 log
			if (param.getResult() != ErrorCode.SUCCESS) {
				if (log.isErrorEnabled()) {
					log.error(param.getResultString());
				}
				return;
			}

			// 顯示 log
			if (log.isInfoEnabled()) {
				log.info(param.getResultString());
			}
		} catch (Exception e) {
			log.error("can't change player item: " + param.getPlayerName() + " result=" + param.getResult(), e);
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 變更角色道具數量
	 * 
	 * @param param
	 *            變更角色金錢和道具的相關參數<br>
	 *            取得變更作業執行結果代碼 {@link MoneyItemChangeParam#getResult() }<br>
	 *            取得道具變更後的新數量 {@link ChangeItem#getNewCount() }
	 */
	public void updatePlayerMoneyItemToDB(MoneyItemChangeParam param) {
		if (param == null) {
			return;
		}

		MoneyChangeParam moneyParam = param.getMoneyParam();
		ItemChangeParam itemParam = param.getItemParam();	
		ChangeCoinLister coinLister = moneyParam.getChangeCoinLister();
		ChangeItemLister itemLister = itemParam.getChangeItemLister();
		ArrayList<UpdateAttribute> updatedAttrList = param.getUpdatedAttrList();
		
		boolean isCoinNull = false;
		boolean isItemNull = false;
		// 幣別和道具清單沒資料
		if (coinLister == null || coinLister.getSize() == 0) {
			isCoinNull = true;
		}
		// 幣別和道具清單沒資料
		if (itemLister == null || itemLister.getSize() == 0) {
			isItemNull = true;
		}
		if(isCoinNull && isItemNull){
			param.setResult(ErrorCode.CHANGE_MONEY_ITEM_NO_DATA);
			return;
		}
		
		try {
			PlayerModel model = null;
			// 扣錢的相關參數檢查
			if (!isCoinNull) {
				// 不會有道具, 所以也不會執行到這邊, mark 起來沒影響
//				model = PlayerDAO.changeMoneyVerify(moneyParam);
				param.setResult(moneyParam.getResult());
			}else{
				model = PlayerDAO.loadPlayerModelByGuid(moneyParam.getPlayerId());
			}

			if (model == null) {
				param.setResult(ErrorCode.NO_PLAYER_DATA);
				return;
			}

			ItemChangeProcessData itemChangeProcData = null;
			// 扣道具的相關參數檢查
			if (!isItemNull) {
				if (param.getResult() == ErrorCode.SUCCESS || param.getResult() == ErrorCode.NULL){
					itemChangeProcData = ItemDAO.changeItemVerify(itemParam);
					param.setResult(itemParam.getResult());
				}
			}

			// 成功後數值套回 db
			if (param.getResult() == ErrorCode.SUCCESS) {
				if (!isItemNull) {
					UpdateAttributeList updateAttributeList = new UpdateAttributeList();
					ItemDAO.changeItemApply(itemParam, itemChangeProcData, updateAttributeList);
					if (updateAttributeList.getUpdateList().size() >= 0) {
						
						if (updatedAttrList == null) {
							updatedAttrList = new ArrayList<UpdateAttribute>();
							param.setUpdatedAttrList(updatedAttrList);
						}
						
						updatedAttrList.addAll(updateAttributeList.getUpdateList());
					}
				}
				if (!isCoinNull) {
//					PlayerDAO.changeMoneyApply(moneyParam, null, null);
				}
			}
			
			if(updatedAttrList != null){				
				PlayerDAO.updatePlayerFromAttrList(model.getGuid(), updatedAttrList, moneyParam.getUserType());
			}
			
			// 失敗顯示 log
			if (param.getResult() != ErrorCode.SUCCESS) {
				if (log.isErrorEnabled()) {
					if (!isItemNull)
						log.error(itemParam.getResultString());
					if (!isCoinNull)
						log.error(moneyParam.getResultString());
				}
				return;
			}

			// 顯示 log
			if (log.isInfoEnabled() && ServerProperties.isSaveConsoleLog(moneyParam.getUserType())) {
				if (!isCoinNull)
					log.info(moneyParam.getResultString());
				if (!isItemNull)
					log.info(itemParam.getResultString());
			}
		} catch (Exception e) {
			log.error("can't change player money or item: " + param.getPlayerName() + "result=" + param.getResult(), e);
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 从DB加载
	 * @param guid
	 * @param putShareMap
	 * @return
	 */
	public Player loadPlayerFromDB(GUID guid, BasicServiceModule currentModule) {
		Account account;
		Player player;
		try {
			player = PlayerDAO.loadPlayerByGuid(guid);
			ItemDAO.LoadItemDataToPlayer(player, currentModule);
			
			account = AccountDAO.loadAccountByAccountId(player.getAccountId());
			
			// 是否為認證會員
			player.setVerifiedMember(account.isVerifiedMember());
			
			// 取得帳號是否已經有角色首儲資訊
			player.setHaveFirstStoreCharacter(account.isHaveFirstStoreCharacter());

			// 帳號是否有設定保險箱密碼
			boolean haveBankPassword = GameUtility.isHaveString(account.getBankPassword());
			player.setHaveBankPassword(haveBankPassword);

			// 是否有認證時間且player尚未記錄領取連續登陸獎勵基準時間
			// 每日獎勵認證部分移除，待確認後刪除 2016/03/04
//			if(account.getRegisterTime() != null && player.getRewardStartTime() == 0){
//				player.setRewardStartTime(account.getRegisterTime().getTimeInMillis());
//			}

			if(log.isInfoEnabled() && ServerProperties.isSaveConsoleLog(player.getUserType())){
				log.info("load from DB guid:" + guid + " Player:" + player);
			}
		} catch (Exception e) {
			log.error("cannot load player:" + guid, e);
			throw new RuntimeException(e);
		}

		if (player != null) {

			player.setLoadTime(System.currentTimeMillis());

			/*
			 * 初始化
			 */
			
			
		}
		return player;
	}
}
